#pragma once

#include <map>
#include <set>
#include <memory>
#include "Types.hpp"
#include "System.hpp"

namespace Alice
{

/* 
    系统管理器
    允许注册系统
    管理所有被注册的系统
*/ 
class SystemMngr
{
public:
    /* 
        注册新系统
        这是一个模板函数
        此函数在注册的同时
        会获取当前系统关注的所有实体
        \param signature   关注的实体签名，用来决定系统关注哪些实体
        \param world       系统所属的世界
    */ 
    template<typename T>
    void Register(Signature signature, World* world);

    /*
        获得系统的实例
        用来设置系统内的值
    */
    template<typename T>
    T* GetSys();

    /*
        调用系统的 Before 函数
        用来初始化数据
    */ 
    void Before();

    /* 
        更新所有系统
        \param dt 当前帧与上一帧的间隔时间
    */ 
    void Update();

    /*
        与 Before 功能相反
    */
    void After();

    /* 
        设置系统的实体集合
        这是专门提供给世界类调用的方法
        以便世界类注册一个新系统时可以更新系统的实体集合
    */ 
    template<typename T>
    void SetEntitys(std::set<Entity> entitys);

    /* 
        更新系统关注的实体
        在实体签名发生变化时
        即添加或删除组件时
        调用此函数来更新系统关注的实体集合
        \param update_type 实体信息变更类型，详情请查看此枚举定义
        \param entity      变更的实体
        \param signature   实体目前的签名
    */ 
    void UpdateEntitys(Entity entity, Signature signature);

private:
    // 每个系统关注的实体签名，用来决定系统关注哪些实体
    std::map<const char*, Signature> m_type_to_signature;
    // 被注册的系统
    std::map<const char*, std::shared_ptr<System> > m_type_to_system;
};

template<class T>
void SystemMngr::Register(Signature signature, World* world)
{
    // 若当前类不是继承自 System 则报错
    static_assert(
        std::is_base_of<System, T>::value,
        "This class does not inherit from System!"
    );

    const char* type_name = typeid(T).name();
    if (m_type_to_signature.find(type_name) == m_type_to_signature.end())
    {
        m_type_to_signature.insert({type_name, signature});
        m_type_to_system.insert({type_name, std::make_shared<T>()});
    }
    // 记录实体管理器
    m_type_to_system.find(type_name)->second->world = world;
}

/*
    @TODO:
    这个函数有缺陷待修复：
    若类型继承自 System 但却未注册过
    函数此时不会报错，会造成函数返回值未知的风险
*/
template<class T>
T* SystemMngr::GetSys()
{
    const char* type_name = typeid(T).name();
    
    // 如果该类型系统不存在则报错
    static_assert(
        std::is_base_of<System, T>::value,
        "This class does not inherit from System!"
    );

    return static_cast<T*>(m_type_to_system[ type_name ].get());
}

template<class T>
void SystemMngr::SetEntitys(std::set<Entity> entitys)
{
    static_assert(
        std::is_base_of<System, T>::value,
        "This class does not inherit from System!"
    );

    const char* type_name = typeid(T).name();
    // 更新系统订阅的实体集合
    m_type_to_system.find(type_name)->second->entitys = entitys;
}

} // namespace Alice
